使用模型(X文件) |
您所在的位置:网站首页 › 种族模型 网格 动画 › 使用模型(X文件) |
在本章的前半部分,介绍了如何使用网格模型来建立地形或简单的三维图形。接下来,看看如何把三维建模软件生成的复杂三维模型导入程序中。流行的3D文件格式现在有很多种,比如.3ds、.max,.cof等,它们包含了许多信息,并且都不为像游戏引擎这样的实时环境所优化。游戏需要更快、更简单的文件格式。根据游戏类型的不同,每个游戏使用的文件格式也各不相同,比如,Quake引擎所使用的文件格式就是.md3的模型格式。
首先,看看最简单的3D文件格式.X,这是Direct3D所使用的格式,下面就研究一下.X格式的模型文件。 5.3.1 X文件格式.X文件格式包含了两个最基本的部分:用户自定义的数据类型和层级关系。X文件是由模板(template)驱动的,模板定义了如何存储一个数据对象,这样用户便可以自己来定义具体的格式。预定义的模板位于rmxftmpl.h和rmxftmpl.x中,模板的标识符都在rmxfguid.h中,通用文件d3dfile.cpp包含了这两个头文件。模板所允许的数据类型被称为“可选成员(optional member)”,这些可选对象作为数据对象的子对象来保存。子对象可以是另一个数据对象,可以是对前一个数据对象的引用,也可以是一个二进制的对象。 X文件格式包含了下面几个主要部分。 1.首部(Header)首部是X文件起始的部分,起始的4字节是魔数(magic number)“xof”,主版本号为03,次版本号也为03。“txt”代表文本文件格式,“bin”代表二进制文件格式。下面是一个典型的X文件的文件头: xof 0303txt 0032 2.帧(Frame)这个模板用来存储一个帧,帧是层次场景的构造元素。帧有它们自己的转换矩阵,还可以有自己的子对象(child objects)。帧也可以有子帧。在skin meshes中,骨骼(bone)指的就是一个帧。 3.变换矩阵(FrameTransformMatrix)正所谓人如其名,这个变换矩阵是帧的变换。它在Frame模板里有实例。下面的文件片断描述一个帧chr_h_047,该帧带有一个子帧,有一个mesh格式的子对象: Frame chr_h_047 { FrameTransformMatrix { 1.000000,0.000000,0.000000,0.000000,0.000000,0.000000,-1.000000, 0.000000,0.000000,1.000000,0.000000,0.000000,-0.323429,-35.371239, 1.476196,1.000000;; } Frame { FrameTransformMatrix { 1.000000,0.000000,0.000000,0.000000,0.000000,1.000000,0.000000, 0.000000,0.000000,0.000000,1.000000,0.000000,0.016750,0.671672, -31.375168,1.000000;; } Mesh { } 4.网格模型(Mesh)这个模板存储一个表态的mesh和mesh的材质。在skin meshes里,整个角色将只是一个mesh,由皮肤信息(skinning information)确定mesh中的每一个部分是如何受到骨骼的影响的。mesh在内部会分成几个子集,每一个子集将受到一个特定的骨骼集合的影响。 5.XskinMeshHeader这个模板存储随mesh一起导出的(exported)关于皮肤信息的属性(nature)。这个模板包含在mesh模板里面。 template XSkinMeshHeader { WORD nMaxSkinWeightsPerVertex; WORD nMaxSkinWeightsPerFace; WORD nBones; } 6.SkinWeights真正的皮肤信息就存储在这里,这个模板定义了一个特定的骨骼能够去影响一个mesh。这个模板在每一个影响到mesh的骨骼里面都有实例。例如,有12个骨骼影响到mesh,mesh模板里将有12个SkinWeights模板的实例。 template SkinWeights { STRING transformNodeName; DWORD nWeights; array DWORD vertexIndices[nWeights]; array FLOAT weights[nWeights]; Matrix4x4 matrixOffset; } 如果建立的是带有骨骼动画的模型,它和静态模型最大的区别就在于骨骼动画模型必须有XskinMeshHeader和SkinWeights模板。如果把这两个模板从任何一个skin mesh里面移走的话,就会得到一个静态的mesh(static mesh)。 7.VertexDuplicationIndices模型的索引缓冲区格式: template VertexDuplicationIndices { DWORD nIndices; DWORD nOriginalVertices; array DWORD indices[nIndices]; } 8.材质和纹理模型的材质和纹理信息都包含在Mesh中,可以直接从X文件里读取材质和纹理信息。纹理是以文件的形式存储的: Material { 1.000000;1.000000;1.000000;1.000000;; 0.000000; 1.000000;1.000000;1.000000;; 0.000000;0.000000;0.000000;; TextureFilename { ".//chr_h_047.bmp"; } } 9.动画在X文件里包含了一个动画集(AnimationSet),每个动画集里的动画都属于对某个框架的引用。例如:下面的X文件动画集就分别是对帧Scene_Root和chr_h_047的引用: AnimationSet { Animation { AnimationKey { 4; 2; …0;16;1.000000,0.000000,0.000000,0.000000,0.000000,1.000000, 0.000000,0.000000,0.000000,0.000000,1.000000,0.000000,0.000000,0.000000,0.000000,1.000000;;, } { Scene_Root } } Animation { AnimationKey { 4; 2; … 16160;16;1.000000,0.000000,0.000000,0.000000,0.000000,0.000000, -1.000000,0.000000,0.000000,1.000000,0.000000,0.000000,-0.323429,-35.371239,1.476196,1.000000;;; } { chr_h_047 } } } 5.3.2 输出.X文件格式可以有多种方法来得到X文件。首先需要使用三维建模软件来建立需要的三维模型,如3DS Max、MAYA。接着,可以使用三维建模软件的插件来导出X文件。 可以使用的导出插件包括XSkinExp、Panda等,从实用角度看,Panda更胜一筹。无论是导出静态模型,还是导出带有骨骼动画的动态模型,一般都不会出问题。这个插件可从下面这个网址下载:http://www.andytather.co.uk /Panda/directxmax_downloads.aspx。 Panda针对不同的3DSM ax版本,有不同版本的插件与之对应,在使用时只要把PandaDXExport*.dle(*对应的是版本)这个文件放在3DS Mas安装目录下的plugins目录中就可以了,3DS Mas在启动后会自动识别这个插件。 在3DS Max中打开一个模型,并单击“输出”按钮后,弹出如图5-10所示的保存对话框,选择Panda对应的保存格式,并单击“打开”按扭。在弹出的保存选项对话框中按图5-11~图5-14的指示进行选择即可。 图5-10 Panda插件的保存类型 图5-11 对象参数 图5-12 动画参数 图5-13 纹理的设置 图5-14 X文件格式的设置 经过一系列正确设置后,就会导出一个相应的X文件。同时这个X文件中用到的位图文件也会一并导出。输出文件后,应该检查一下文件内容对不对,这个时候可以用DirectX中自带的观看模型工具Mesh Viewer来看,如图5-15所示。 图5-15 用Mesh Viewer工具查看导出的模型 5.3.3 在Direct3D程序中载入X文件在Direct3D中,3D模型都是以网格模型的形式使用的,它将数据从X文件中读出,通过函数D3DCreateMesh()来创建3D图形。不过通常情况下不用显式地调用函数D3DcreateMesh(),它已经被封装在其他Direct3D功能扩展库函数中。 1.从文件中读取网格模型函数D3DXLoadMeshFromX()用于从X文件中提取多边形网格信息(包括顶点坐标、颜色、法线向量、纹理信息等),生成多边形网格。函数声明如下: HRESULT D3DXLoadMeshFromX( LPCTSTR pFilename, //X文件路径和文件名 DWORD Options, //指定生成多边形网格属性 LPDIRECT3DDEVICE9 pDevice, //Direct3D设备指针 LPD3DXBUFFER* ppAdjacency, //存储临近多边形信息的内存地址 LPD3DXBUFFER* ppMaterials, //存储材质的内存地址 LPD3DXBUFFER* ppEffectInstances, //存储模型特殊效果的内存地址 DWORD* pNumMaterials, //存储材质数目的内存地址 LPD3DXMESH* ppMesh //存储生成的多边形网格的内存地址 ); 其中,LPD3DXBUFFER可以存储如顶点缓冲区、材质、纹理等多种类型的Direct3D数据,而不必对每一种数据声明一个函数接口类型。 下面的函数片断从名为“game”的X文件里读取3D模型: if( FAILED( D3DXLoadMeshFromX( "game.x", D3DXMESH_SYSTEMMEM, g_pd3dDevice, NULL, &pD3DXMtrlBuffer,NULL, &g_dwNumMaterials, &g_pMesh ) ) ) { return E_FAIL; } 2.载入纹理和材质函数D3DXLoadMeshFromX()调用成功后,参数pNumMaterials就会获得 X文件中三维模型的材质和纹理信息,而pNumMaterials会存储材质的数目。 下面的程序片断用于获取3D模型的材质和纹理信息。 【例5-5】得到模型中的材质和纹理信息: // 从材质集合中把材质和纹理信息解压读取出来 D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer(); g_pMeshMaterials = new D3DMATERIAL9[g_dwNumMaterials]; g_pMeshTextures = new LPDIRECT3DTEXTURE9[g_dwNumMaterials]; for( DWORD i=0; i g_pMeshTextures[i] = NULL; } } // 释放材质缓冲区的内容 pD3DXMtrlBuffer->Release(); 3.绘制网格模型最后,调用函数DrawSubset()绘制多边形网格的3D模型,如图5-12所示。 // 用循环绘制每一个网格面。 for( DWORD i=0; i |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |